﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Modbus.Device;






namespace PickAndPlaceXYZ
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
            System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
            //设置该属性 为false,在多线程程序中,新创建的线程不能访问UI线程创建的窗口控件
            //这个时候如果你想要访问窗口的控件,那么你可以将窗口构造函数
            //中的CheckForIllegalCrossThreadCalls设置为false.这时线程就
            //能安全的访问窗体控件了
        }

        #region 属性变量
        TcpClient tcpClient;
        ModbusIpMaster master;
        string ipAddress;
        int tcpPort;
        bool NetworklsOk = false;
        string stepState;

        DateTime dtDisconnect = new DateTime();
        DateTime dtNow = new DateTime();


        //输入
        bool[] InputsRead;
        ushort[] InputRegistersRead;
        public bool BoxAtPlace;
        bool PartAtPlace;
        bool Detected;
        bool CLimit;
        bool Start;
        bool Reset;
        bool Stop;
        bool E_Stop;
        bool Auto;
        bool Factory_reset;
        ushort Xinput;
        ushort Yinput;
        ushort Zinput;
        //输出
        bool[] ResultCoilRead = { false, false, false, false, false, false, false, false, false, false, false };
        ushort[] xyzoutput = { 0, 0, 0 };
        bool BoxConveyor = false;
        bool PartConveyor = false;
        bool ExitConveyor = false;
        bool CRotate = false;
        bool Grab = false;
        bool ExitGreen = false;
        bool ExitYellow = false;
        bool ExitRed = false;
        bool StartLight = false;
        bool ResetLight = false;
        bool StopLight = false;
        ushort Xoutput = 0;
        ushort Youtput = 0;
        ushort Zoutput = 0;
        public ushort XPickPosition { get; set; }
        public ushort YPickPosition { get; set; }
        public ushort ZPickPosition { get; set; }
        public ushort XPlacePosition1 { get; set; }
        public ushort XPlacePosition2 { get; set; }
        public ushort XPlacePosition3 { get; set; }
        public ushort YPlacePosition1 { get; set; }
        public ushort YPlacePosition2 { get; set; }
        public ushort YPlacePosition3 { get; set; }

        ushort XstartAdress = 0;
        ushort YstartAdress = 1;
        ushort ZstartAdress = 2;

        byte deviceID = 1;
        ushort startaddress = 0;
        ushort numOfPoints = 10;
        int step = 0;

        #endregion

        #region 窗体加载
        /// <summary>
        /// 加载窗体时，赋初值。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            textBoxIP.Text = "192.168.56.1";
            textBoxPort.Text = "503";
            tcpClient = new TcpClient();
            Read("D:\\VS\\PickAndPlaceXYZ\\position.txt");
            toolStripLabelStateMessage.Text = "文件加载完毕，初始化成功";
        }
        #endregion

        #region 建立TCP连接
        /// <summary>
        /// 建立连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnConnect_Click(object sender, EventArgs e)
        {
            try
            {
                //如果没有连接
                if (!tcpClient.Connected)
                {
                    ipAddress = textBoxIP.Text;
                    tcpPort = Convert.ToInt32(textBoxPort.Text.Trim());
                    tcpClient = new TcpClient();//创建一个客户端对象，我理解factory是客户端，我们本身是master
                    tcpClient.BeginConnect(ipAddress, tcpPort, null, null);
                    master = ModbusIpMaster.CreateIp(tcpClient);
                    master.Transport.ReadTimeout = 1500;
                    Thread.Sleep(10);
                    if (tcpClient.Connected)
                    {
                        textBoxMessage.AppendText(DateTime.Now.ToString() + ":服务器已连接,端口为：" + tcpPort + "\r\n");
                        btnConnect.Text = "断开";
                        toolStripLabelStateMessage.Text = "服务器已连接";
                        NetworklsOk = true;
                    }
                    if (!tcpClient.Connected)
                    {
                        textBoxMessage.AppendText(DateTime.Now.ToString() + ":无法连接到服务器，请检查IP地址和端口" + "\r\n");
                        toolStripLabelStateMessage.Text = "服务器无法连接";
                    }
                }
                else
                {
                    //如果已经连接
                    if (tcpClient.Connected)
                    {
                        tcpClient.Close();
                        tcpClient.Dispose();
                        master.Dispose();

                        textBoxMessage.AppendText(DateTime.Now.ToString() + ":服务器已断开" + "\r\n");
                        btnConnect.Text = "连接";
                        toolStripLabelStateMessage.Text = "服务器已断开";
                        NetworklsOk = false;
                    }
                }
            }
            catch (Exception)
            {

                MessageBox.Show("没有找到相应的服务器！");
            }
            

        }
        #endregion

        #region 读取离散输入，手动按钮测试
        /// <summary>
        /// 读取离散输入，手动按钮测试
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonRead_Click(object sender, EventArgs e)
        {
            if (NetworklsOk)
            {
                byte deviceID = 1;
                ushort startaddress = 0;
                ushort numOfPoints = 10;
                bool[] ResultInputRead = master.ReadInputs(deviceID, startaddress, numOfPoints);
                for (int i = 0; i < numOfPoints; i++)
                {
                    textBoxMessage.AppendText(ResultInputRead[i] + "\r\n");
                }
            }
            else
            {
                MessageBox.Show("服务器要先连接", "确认");
            }
        }
        #endregion

        #region 写入一系列线圈
        /// <summary>
        /// 写入一系列线圈
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonWrite_Click(object sender, EventArgs e)
        {
            if (NetworklsOk)
            {
                byte deviceID = 1;
                ushort startaddress = 0;
                bool[] ResultCoilsWrite = { true, true, false };
                master.WriteMultipleCoils(deviceID, startaddress, ResultCoilsWrite);
                for (int i = 0; i < ResultCoilsWrite.Length; i++)
                {
                    textBoxMessage.AppendText(ResultCoilsWrite[i] + "被写入" + "\r\n");
                }
            }
            else
            {
                MessageBox.Show("服务器要先连接", "确认");
            }
        }
        #endregion

        #region 测试连接的启动按钮，开启了另外一个线程
        /// <summary>
        /// 测试连接的启动按钮
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonStart_Click(object sender, EventArgs e)
        {
            if (NetworklsOk)
            {
                Thread thread1 = new Thread(new ThreadStart(logic));
                thread1.Start();
                
            }
            else
            {
                MessageBox.Show("服务器要先连接", "确认");
            }
        }
        #endregion

        #region 自动化逻辑处理
        /// <summary>
        /// 自动化逻辑处理
        /// </summary>
        private void logic()
        {
            try
            {
                int number = 0;
                int layer = 0;
                bool BoxFull = false;
                var textBoxMessageNumber = 0;
                while (true)
                {
                    //timer1.Enabled = true;
                    //读取输入，并转换
                    InputsRead = master.ReadInputs(deviceID, startaddress, numOfPoints);
                    InputRegistersRead = master.ReadInputRegisters(deviceID, startaddress, numOfPoints);

                    //for (int i = 0; i < 2; i++)
                    //{
                    //    textBoxMessage.AppendText("输入变量" + i + ":" + InputsRead[i] + "\r\n");
                    //}
                    BoxAtPlace = InputsRead[0];
                    PartAtPlace = InputsRead[1];
                    Detected = InputsRead[2];
                    CLimit = InputsRead[3];
                    Start = InputsRead[4];
                    Reset = InputsRead[5];
                    Stop = InputsRead[6];
                    E_Stop = InputsRead[7];
                    Auto = InputsRead[8];
                    Factory_reset = InputsRead[9];

                    Xinput = InputRegistersRead[0];
                    Yinput = InputRegistersRead[1];
                    Zinput = InputRegistersRead[2];
                    //逻辑输出

                    //PartConveyor = FactoryIO_Logic.ConveyorLogic(PartAtPlace);
                    //BoxConveyor = FactoryIO_Logic.ConveyorLogic(BoxAtPlace);

                    if (Factory_reset)
                    {
                        Xoutput = 0;
                        Youtput = 0;
                        Zoutput = 0;
                        step = 0;
                    }

                    FactoryIO_Logic factoryIO_Logic = new FactoryIO_Logic();

                    StartLight = factoryIO_Logic.ConveyorLogic(Start);

                    ResetLight = factoryIO_Logic.ConveyorLogic(Reset);

                    StopLight = factoryIO_Logic.ConveyorLogic(Stop);

                    switch (step)
                    {
                        case 0:
                            //Thread.Sleep(1000);
                            //BoxConveyor = ConveyorLogic(BoxAtPlace);
                            //master.WriteSingleCoil(deviceID, startaddress, BoxConveyor);

                            if (BoxAtPlace || BoxFull)
                            {
                                BoxConveyor = true;
                                master.WriteSingleCoil(deviceID, startaddress, BoxConveyor);
                            }
                            if (!BoxAtPlace && !BoxFull)
                            {
                                BoxConveyor = false;
                            }
                            if (BoxFull)
                            {
                                Thread.Sleep(1600);
                                BoxFull = false;
                            }

                            PartConveyor = factoryIO_Logic.ConveyorLogic(PartAtPlace);
                            //master.WriteSingleCoil(deviceID, 1, BoxConveyor);
                            if (!PartAtPlace && !BoxAtPlace)
                            {
                                step = 1;
                            }
                            break;
                        case 1://去取料位
                            if (!PartConveyor && !BoxConveyor)
                            {
                                Xoutput = XPickPosition;
                                Youtput = YPickPosition;
                                Zoutput = ZPickPosition;
                                stepState = "到达取料位";
                                step = 2;
                            }
                            break;
                        case 2://吸取物料
                            if (System.Math.Abs(Xinput - XPickPosition) < 2 && System.Math.Abs(Yinput - YPickPosition) < 2 && System.Math.Abs(Zinput - ZPickPosition) < 2)
                            //if (System.Math.Abs(Xinput - XPickPosition) < 0.01 && System.Math.Abs(Yinput - YPickPosition) < 0.01 && System.Math.Abs(Zinput - ZPickPosition) < 0.01)
                            {
                                Grab = true;
                                stepState = "吸取物料完成";
                                step = 3;
                            }
                            Console.WriteLine("还在执行");
                            break;
                        case 3://Z轴稍微抬起一点
                            if (Grab && Detected)
                            {
                                Zoutput = 2;
                                stepState = "带料上升";
                                step = 4;
                            }
                            break;
                        case 4://去放料位
                            if (Grab && Detected && System.Math.Abs(Zinput - Zoutput) < 2)
                            {
                                if (number == 0)
                                {
                                    Xoutput = XPlacePosition1;
                                    Youtput = YPlacePosition1;
                                }
                                if (number == 1)
                                {
                                    Xoutput = XPlacePosition2;
                                    Youtput = YPlacePosition2;
                                }
                                if (number == 2)
                                {
                                    Xoutput = XPlacePosition3;
                                    Youtput = YPlacePosition3;
                                }
                                stepState = "到达放料位";
                                step = 5;
                            }
                            break;
                        case 5://Z轴下降
                            if (System.Math.Abs(Xinput - Xoutput) < 2 && System.Math.Abs(Yinput - Youtput) < 2)
                            {
                                if (layer == 0)
                                {
                                    Zoutput = 10;
                                }
                                if (layer == 1)
                                {
                                    Zoutput = 9;
                                }
                                stepState = "带料下降";
                                step = 6;
                            }
                            break;
                        case 6://放产品
                            if (System.Math.Abs(Xinput - Xoutput) < 2 && System.Math.Abs(Yinput - Youtput) < 2 && System.Math.Abs(Zinput - Zoutput) < 2)
                            {
                                Thread.Sleep(1000);
                                Grab = false;
                                stepState = "放料完成";
                                number += 1;
                                if (number == 3)
                                {
                                    number = 0;
                                    layer += 1;
                                    if (layer == 2)
                                    {
                                        BoxFull = true;
                                        //System.Threading.Thread.Sleep(2000);
                                        layer = 0;
                                    }
                                    step = 0;
                                }
                                if (number < 3)
                                {
                                    step = 0;
                                }
                            }
                            break;
                    }

                    if (textBoxMessageNumber!=step)
                    {
                        textBoxMessage.AppendText("step=:" + step + "  " + stepState + "\r\n");
                        textBoxMessageNumber = step;
                    }
                   

                    ResultCoilRead[0] = BoxConveyor;
                    ResultCoilRead[1] = PartConveyor;
                    ResultCoilRead[2] = ExitConveyor;
                    ResultCoilRead[3] = CRotate;
                    ResultCoilRead[4] = Grab;
                    ResultCoilRead[5] = ExitGreen;
                    ResultCoilRead[6] = ExitYellow;
                    ResultCoilRead[7] = ExitRed;
                    ResultCoilRead[8] = StartLight;
                    ResultCoilRead[9] = ResetLight;
                    ResultCoilRead[10] = StopLight;

                    xyzoutput[0] = Xoutput;
                    xyzoutput[1] = Youtput;
                    xyzoutput[2] = Zoutput;
                    master.WriteMultipleCoils(deviceID, startaddress, ResultCoilRead);
                    master.WriteMultipleRegisters(deviceID, startaddress, xyzoutput);
                    //for (int i = 0; i < 2; i++)
                    //{
                    //    textBoxMessage.AppendText("输出变量" + i + ":" + ResultCoilRead[i] + "被写入" + "\r\n");
                    //}
                    xyzshow();
                    System.Threading.Thread.Sleep(150);

                }
                textBoxMessage.AppendText("这是while循环之后" + "\r\n");//根本执行不到这里
            }
            catch (Exception)
            {
                MessageBox.Show("服务器要先连接", "确认");
            }
        }
        #endregion

        #region 手动模式
        /// <summary>
        /// 手动模式
        /// </summary>
        private void buttonXadd_Click(object sender, EventArgs e)
        {
            Xoutput = ManualAdd(XstartAdress, Xoutput);
            xyzshow();
        }

        private void buttonXsubtract_Click(object sender, EventArgs e)
        {
            Xoutput = ManualSubtract(XstartAdress, Xoutput);
            xyzshow();
        }

        private void buttonYadd_Click(object sender, EventArgs e)
        {
            Youtput = ManualAdd(YstartAdress, Youtput);
            xyzshow();
        }

        private void buttonYsubtract_Click(object sender, EventArgs e)
        {
            Youtput = ManualSubtract(YstartAdress, Youtput);
            xyzshow();
        }

        private void buttonZadd_Click(object sender, EventArgs e)
        {
            Zoutput = ManualAdd(ZstartAdress, Zoutput);
            xyzshow();
        }

        private void buttonZsubtract_Click(object sender, EventArgs e)
        {
            Zoutput = ManualSubtract(ZstartAdress, Zoutput);
            xyzshow();
        }

        private ushort ManualAdd(ushort startaddress, ushort num)
        {
            byte deviceID = 1;
            num++;
            master.WriteSingleRegister(deviceID, startaddress, num);
            if (num >= 10)
            {
                num = 10;
            }
            return num;
        }

        private ushort ManualSubtract(ushort startaddress, ushort num)
        {
            byte deviceID = 1;
            num--;
            master.WriteSingleRegister(deviceID, startaddress, num);
            if (num > 10)
            {
                num = 0;
            }
            return num;
        }
        #endregion

        #region 存入作业位置
        private void btnPick_Click(object sender, EventArgs e)
        {
            XPickPosition = Xoutput;
            YPickPosition = Youtput;
            ZPickPosition = Zoutput;
            FileStream fs = new FileStream("D:\\VS\\PickAndPlaceXYZ\\position.txt", FileMode.Create);
            StreamWriter sw = new StreamWriter(fs);
            //开始写入
            sw.Write("XPickPosition = {0}\n"+ "YPickPosition = {1}\n"+ "zPickPosition = {2}\n", XPickPosition, YPickPosition, ZPickPosition);
            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            fs.Close();
            textBoxMessage.AppendText($"写入：\r\nXPickPosition = {XPickPosition}\r\nYPickPosition = {YPickPosition}\r\nZPickPosition = {ZPickPosition}\r\n");
        }

            

        private void btnPlace1_Click(object sender, EventArgs e)
        {
            XPlacePosition1 = Xoutput;
            YPlacePosition1 = Youtput;
            StreamWriter sw = new StreamWriter("D:\\VS\\PickAndPlaceXYZ\\position.txt",true);
            //开始写入
            sw.Write("XPlacePosition1 = {0}\n" + "YPlacePosition1 = {1}\n", XPlacePosition1, YPlacePosition1);
            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            textBoxMessage.AppendText($"写入：\r\nXPlacePosition1 = {XPlacePosition1}\r\nYPlacePosition1 = {YPlacePosition1}\r\n");
        }

        private void btnPlace2_Click(object sender, EventArgs e)
        {
            XPlacePosition2 = Xoutput;
            YPlacePosition2 = Youtput;
            StreamWriter sw = new StreamWriter("D:\\VS\\PickAndPlaceXYZ\\position.txt", true);
            //开始写入
            sw.Write("XPlacePosition2 = {0}\n" + "YPlacePosition2 = {1}\n", XPlacePosition2, YPlacePosition2);
            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            textBoxMessage.AppendText($"写入：\r\nXPlacePosition2 = {XPlacePosition2}\r\nYPlacePosition2 = {YPlacePosition2}\r\n");
        }

        private void btnPlace3_Click(object sender, EventArgs e)
        {
            XPlacePosition3 = Xoutput;
            YPlacePosition3 = Youtput;
            StreamWriter sw = new StreamWriter("D:\\VS\\PickAndPlaceXYZ\\position.txt", true);
            //开始写入
            sw.Write("XPlacePosition3 = {0}\n" + "YPlacePosition3 = {1}\n", XPlacePosition3, YPlacePosition3);
            //清空缓冲区
            sw.Flush();
            //关闭流
            sw.Close();
            textBoxMessage.AppendText($"写入：\r\nXPlacePosition3 = {XPlacePosition3}\r\nYPlacePosition3 = {YPlacePosition3}\r\n");
        }
        #endregion

        #region 窗体关闭，释放连接
        /// <summary>
        /// 窗体关闭，释放连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (NetworklsOk)
            {
                tcpClient.Close();
                NetworklsOk = false;
                //thread1.Close();                 // 只是关闭当前窗口，若不是主窗体的话，是无法退出程序的，另外若有托管线程（非主线程），也无法干净地退出；
                Application.Exit();           // 强制所有消息中止，退出所有的窗体，但是若有托管线程（非主线程），也无法干净地退出；
                Application.ExitThread();
                System.Environment.Exit(0);//这是最彻底的退出方式，不管什么线程都被强制退出，把程序结束的很干净。
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            System.Environment.Exit(0);
        }
        #endregion

        #region 窗口画面显示
        /// <summary>
        /// 窗口画面显示
        /// </summary>
        public void xyzshow()
        {
            textBoxXinput.Text = Xinput.ToString();
            textBoxYinput.Text = Yinput.ToString();
            textBoxZinput.Text = Zinput.ToString();
            textBoxXoutput.Text = Xoutput.ToString();
            textBoxYoutput.Text = Youtput.ToString();
            textBoxZoutput.Text = Zoutput.ToString();
        }

        #endregion

        private void btnReadRigisterInput_Click(object sender, EventArgs e)
        {
            ushort[] RegistersReadInput = master.ReadInputRegisters(deviceID, startaddress, numOfPoints);
            //ushort[] RegistersReadInput = new ushort[2] { 59769, 17142 };
            float[] floatData = new float[RegistersReadInput.Length / 2];
            Buffer.BlockCopy(RegistersReadInput,0, floatData,0, RegistersReadInput.Length*2);
            for (int i = 0; i < floatData.Length; i++)
            {
                //Console.WriteLine(floatData[i / 2].ToString("0.0000"));
                Console.WriteLine(string.Format("floatData[{0}]={1}", i, floatData[i / 2].ToString()));
            }


            for (int i = 0; i < RegistersReadInput.Length; i++)
            {
                textBoxMessage.AppendText($"输入{i}={RegistersReadInput[i]} \r\n");
                if (i==9)
                {
                    textBoxMessage.AppendText($"-------------------- \r\n");
                }
            }
            
        }

        private void btnWriteRigisterOutput_Click(object sender, EventArgs e)
        {
            //写
            ushort[] uintData = new ushort[2];
            float[] floatData = new float[1] { 3.14f };
            Buffer.BlockCopy(floatData,0,uintData,0,4);
            for (int i = 0; i < uintData.Length; i++)
            {
                Console.WriteLine(string.Format("uintData[{0}]={1}",i,uintData[i]));
            }
            master.WriteMultipleRegisters(deviceID, startaddress, uintData);
        }
        public void Read(string path)
        {
            StreamReader sr = new StreamReader(path, Encoding.Default);
            String[] line = new string[100];
            ushort[] bufferPosition = new ushort[100];
            int nLines = 1;
            
            for (int i = 0; i < nLines; i++)
            {
                if ((line[i] = sr.ReadLine()) != null)
                {
                    ++nLines;
                }
                else
                {
                    break;
                }
                Console.WriteLine(i.ToString() + ":" + line[i]);
                textBoxMessage.AppendText(i.ToString() + ":" + line[i]+"\r\n");
                string[] strArray = line[i].Split( new char[] { ' '});
                bufferPosition[i] = (ushort)Convert.ToInt16(strArray[2]);
            }
            XPickPosition = bufferPosition[0];
            YPickPosition = bufferPosition[1];
            ZPickPosition = bufferPosition[2];
            XPlacePosition1 = bufferPosition[3];
            YPlacePosition1 = bufferPosition[4];
            XPlacePosition2 = bufferPosition[5];
            YPlacePosition2 = bufferPosition[6];
            XPlacePosition3 = bufferPosition[7];
            YPlacePosition3 = bufferPosition[8];
            textBoxMessage.AppendText("文件加载完毕！\r\n");
            sr.Close();
            //while ((line = sr.ReadLine()) != null)
            //{

            //    Console.WriteLine(i.ToString()+":"+line);
            //    i++;
            //}
        }
    }
}



